//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

#include <stdlib.h>
#include <stdio.h>
#include <windows.h>
#include <winioctl.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>

#define DriveName   "\\\\.\\M:"

static HANDLE g_hDrive = 0;
void __cdecl DriveClose(void)
{
    if (g_hDrive) {
        CloseHandle(g_hDrive);
        g_hDrive = 0;
    }
}

BOOL
GetDiskGeometry(
    HANDLE hDisk,
    PDISK_GEOMETRY lpGeometry
    )
{
    DWORD ReturnedByteCount;

    return DeviceIoControl(
                hDisk,
                IOCTL_DISK_GET_DRIVE_GEOMETRY,
                NULL,
                0,
                lpGeometry,
                sizeof(*lpGeometry),
                &ReturnedByteCount,
                NULL);
}

void
PrintGeometry(
    PDISK_GEOMETRY lpGeometry
    )
{
    LPSTR MediaType;

    printf("    Geometry for Drive %s\n",DriveName);

    switch (lpGeometry->MediaType) {
        case F5_1Pt2_512:  MediaType = "5.25, 1.2MB,  512 bytes/sector";break;
        case F3_1Pt44_512: MediaType = "3.5,  1.44MB, 512 bytes/sector";break;
        case F3_2Pt88_512: MediaType = "3.5,  2.88MB, 512 bytes/sector";break;
        case F3_20Pt8_512: MediaType = "3.5,  20.8MB, 512 bytes/sector";break;
        case F3_720_512:   MediaType = "3.5,  720KB,  512 bytes/sector";break;
        case F5_360_512:   MediaType = "5.25, 360KB,  512 bytes/sector";break;
        case F5_320_512:   MediaType = "5.25, 320KB,  512 bytes/sector";break;
        case F5_320_1024:  MediaType = "5.25, 320KB,  1024 bytes/sector";break;
        case F5_180_512:   MediaType = "5.25, 180KB,  512 bytes/sector";break;
        case F5_160_512:   MediaType = "5.25, 160KB,  512 bytes/sector";break;
        case RemovableMedia: MediaType = "Removable media other than floppy";break;
        case FixedMedia:   MediaType = "Fixed hard disk media";break;
        default:           MediaType = "Unknown";break;
    }
    printf("    Media Type %s\n",MediaType);
    printf("    Cylinders %d Tracks/Cylinder %d Sectors/Track %d Bytes/Sector %d\n\n",
        lpGeometry->Cylinders.LowPart,
        lpGeometry->TracksPerCylinder,
        lpGeometry->SectorsPerTrack,
        lpGeometry->BytesPerSector);

    return ;
}

int DriveRW(unsigned long Position, void *pBuffer, int Size, int Flags)
{
    DWORD NewFilePos;
    if (NULL == g_hDrive) {
        // Open and Lock the drive
        g_hDrive = CreateFileA(
                    DriveName, GENERIC_READ | GENERIC_WRITE,
                    FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
        if (g_hDrive == INVALID_HANDLE_VALUE) {
            printf("DRIVE: Open %s failed %d\n",DriveName,GetLastError());
            return 0;
        }

        atexit(DriveClose);

        DISK_GEOMETRY Geometry;
        if (!GetDiskGeometry(g_hDrive, &Geometry)) {
            printf("DRIVE: GetDiskGeometry %s failed %d\n",DriveName,GetLastError());
            return 0;
        }
        PrintGeometry(&Geometry);

        assert(RemovableMedia == Geometry.MediaType);
    }

    NewFilePos = SetFilePointer(g_hDrive, Position, NULL, FILE_BEGIN);
    if (NewFilePos == DWORD(-1)) {
        printf("DRIVE: Set FilePointer failed %d\n", GetLastError());
        return 0;
    }

    DWORD BytesRead;
    BOOL b;
    if (Flags == 0) {//Read sectors
        b = ReadFile(g_hDrive, pBuffer, Size, &BytesRead, NULL);
//        if(b) {
//            printf("READ SUCEED\n");
//        } else {
//            printf("READ FAIL\n");
//        }
    }
    else {//Write Sectors
        b = WriteFile(g_hDrive, pBuffer, Size, &BytesRead, NULL);
        FlushFileBuffers(g_hDrive);//Write out all buffer data
//        if(b) {
//            printf("WRITE SUCEED\n");
//        } else {
//            printf("WRITE FAIL\n");
//        }
    }

    if (!b) {
        printf("DRIVE: IO FAIL\n");
    }
    return BytesRead;
}
